﻿using System.IO.Ports;
using Devonline.Communication.Abstractions;
using Devonline.Core;
using Microsoft.Extensions.Logging;

namespace Devonline.Communication.SerialPorts;

/// <summary>
/// 字节流作为交互数据的串口通讯器
/// </summary>
public class SerialPortStreamCommunicator : SerialPortCommunicator<byte[]>, IStreamCommunicator
{
    public SerialPortStreamCommunicator(ILogger<SerialPortCommunicator<byte[]>> logger, SerialPortOptions setting) : base(logger, setting) { }

    /// <summary>
    /// 将字节流写入串口
    /// </summary>
    /// <param name="data"></param>
    public override Task SendAsync(byte[] data) => Task.Run(() =>
    {
        ArgumentNullException.ThrowIfNull(_serialPort);
        if (_serialPort.IsOpen && data != null && data.Length > 0)
        {
            try
            {
                var value = data.ToHexString();
                _logger.LogDebug(LOG_COMMUNICATOR + $"数据 {value}" + " 将写入到串口 {com} 中", _options.Communicator, _setting.PortName);
                _serialPort.Write(data, 0, data.Length);
                _logger.LogInformation(LOG_COMMUNICATOR + $"数据 {value}" + " 已写入到串口 {com} 中", _options.Communicator, _setting.PortName);
            }
            catch (Exception ex)
            {
                OnError(ex);
            }
        }
    });

    /// <summary>
    /// 串口收到数据后触发的事件委托方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected override void OnReceive(object sender, SerialDataReceivedEventArgs e)
    {
        ArgumentNullException.ThrowIfNull(_serialPort);
        if (_serialPort.IsOpen)
        {
            try
            {
                var buffer = new byte[_setting.BufferSize];
                var count = _serialPort.Read(buffer, 0, buffer.Length);
                var data = new byte[count];
                Array.Copy(buffer, data, count);
                _logger.LogInformation("收到串口 {com} " + $"数据 {data.ToHexString()}" + ", 事件类型 {eventType}", _setting.PortName, e.EventType);
                OnReceive(data);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "收到串口 {com} 数据, 但读取中出现错误!", _setting.PortName);
            }
        }
    }
}